# -*- coding: UTF-8 -*-
from django.utils import httpwrappers
from django.core import template_loader
from django.core.extensions import DjangoContext as Context
from django.models.auth import sessions, users
from django.views.registration import passwords
import base64, md5
import cPickle as pickle
from django.conf.settings import SECRET_KEY

ERROR_MESSAGE = "Veuillez entrer un nom d'utilisateur et un mot de passe correct. Notez que les deux champs sont sensibles à la casse."

class AdminUserRequired:
    """
    Le module intermédiaire de l'interface d'administration.  Si ce module intermédiaire
    est activé, l'accès au site ne sera accordé qu'aux utilisateurs valides dont l'attribut
    "is_staff" est activé.
    """

    def process_view(self, request, view_func, param_dict):
        """
        S'assure que l'utilisateur est connecté et qu'il constitue un utilisateur
        valide de l'interface d'administration avant de lui autoriser l'accès au site.

        Le module intermédiaire agit au niveau vue car on a besoin de savoir si
        l'utilisateur veut redéfinir son mot de passe.
        """

        # Si la vue actuelle est la vue permettant à un utilisateur de redéfinir son mot de passe,
        # il ne faut pas rendre obligatoire la connexion. Sans ce test, il faudrait ajouter à la
        # configuration d'Apache une entrée dédiée, ce qui, avouons-le, est un peu plus laid.
        if view_func == passwords.password_reset or view_func == passwords.password_reset_done:
            return

        # On vérifie si l'utilisateur est valide et connecté
        if self.user_is_valid(request.user):
            return

        # Si on ne se trouve pas déjà sur la page de connexion, on l'affiche
        if not request.POST.has_key('this_is_the_login_form'):
            if request.POST:
                message = "Veuillez vous connecter de nouveau car votre session a expiré. "\
                          "Ne vous inquiétez pas : vos données ont été enregistrées."
            else:
                message = ""
            return self.display_login_form(request, message)

        # On vérifie le mot de passe
        username = request.POST.get('username', '')
        try:
            user = users.get_object(username__exact=username)
        except users.UserDoesNotExist:
            message = ERROR_MESSAGE
            if '@' in username:
                # L'utilisateur a-t-il entré par mégarde son adresse e-mail à la place de son nom d'utilisateur? C'est ce qu'on regarde.
                try:
                    user = users.get_object(email__exact=username)
                except users.UserDoesNotExist:
                    message = "Les noms d'utilisateur ne peuvent pas contenir le caractère @."
                else:
                    message = "Votre adresse e-mail n'est pas votre nom d'utilisateur. Essayez '%s', plutôt." % user.username
            return self.display_login_form(request, message)

        # Les données de l'utilisateur sont correctes; on connecte l'utilisateur et on continue
        else:
            if self.authenticate_user(user, request.POST.get('password', '')):
                if request.POST.has_key('post_data'):
                    post_data = decode_post_data(request.POST['post_data'])
                    if post_data and not post_data.has_key('this_is_the_login_form'):
                        # on remplace request.POST par post_data qu'on a préservé et on continue
                        request.POST = post_data
                        request.user = user
                        request.session = sessions.create_session(user.id)
                        return
                    else:
                        response = httpwrappers.HttpResponseRedirect(request.path)
                        sessions.start_web_session(user.id, request, response)
                        return response
            else:
                return self.display_login_form(request, ERROR_MESSAGE)

    def display_login_form(self, request, error_message=''):
        if request.POST and request.POST.has_key('post_data'):
            # L'utilisateur n'a pas réussi à se connecter MAIS des données 'post_data' ont été préservées
            post_data = request.POST['post_data']
        elif request.POST:
            # La session de l'utilisateur a dû expirer; on enregistre les données POST
            post_data = encode_post_data(request.POST)
        else:
            post_data = encode_post_data({})
        t = template_loader.get_template(self.get_login_template_name())
        c = Context(request, {
            'title': 'Connexion',
            'app_path': request.path,
            'post_data': post_data,
            'error_message': error_message
        })
        return httpwrappers.HttpResponse(t.render(c))

    def authenticate_user(self, user, password):
        return user.check_password(password) and user.is_staff

    def user_is_valid(self, user):
        return not user.is_anonymous() and user.is_staff

    def get_login_template_name(self):
        return "login"

def encode_post_data(post_data):
    pickled = pickle.dumps(post_data)
    pickled_md5 = md5.new(pickled + SECRET_KEY).hexdigest()
    return base64.encodestring(pickled + pickled_md5)

def decode_post_data(encoded_data):
    encoded_data = base64.decodestring(encoded_data)
    pickled, tamper_check = encoded_data[:-32], encoded_data[-32:]
    if md5.new(pickled + SECRET_KEY).hexdigest() != tamper_check:
        from django.core.exceptions import SuspiciousOperation
        raise SuspiciousOperation, "Il est probable que l'utilisateur ait modifié le cookie de session."
    return pickle.loads(pickled)
